package edu.hawaii.halealohacli.jcev.command;

import java.text.DecimalFormat;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.resource.sensordata.jaxb.SensorData;
import org.wattdepot.resource.source.jaxb.Source;

/**
 * Returns the amount of energy used for a given day.
 * @author Eldon Visitacion
 *
 */
public class DailyEnergy implements Command {
  /** name of the source. */
  private String sourceName;
  /** date, in string format [yyyy-dd-mm]. */
  private String dayString;
  /** to hold sensor data. */
  private SensorData data;
  /** to hold sensor data. */
  private SensorData data2;
  /** 23:59:59 of given day. */
  private XMLGregorianCalendar startTime;
  /** 0:0:0 of given day. */
  private XMLGregorianCalendar endTime;
  /** energy used, in kilowatts. */
  private double kilosUsed;
  /** for testing. checks if there is a error w/ arguments. */
  private boolean testArg;
  Exception dateFormat = new Exception("Error: Incorrect date format."
      + "Correct format: yyyy-mm-dd");
  Exception incorrectArguments = new Exception("Error: Command requires 2 arguments.\n"
     + "Correct syntax: daily-energy [tower | lounge] [date]");
  
  /**
   * Create an object which gets the Daily Energy usage.
   * @param client The WattDepotClient which is being used to collect the data.
   * @param name The WattDepot Source name
   * @param day date in string format
   * @return DailyEnergy Object
   * @throws Exception A generic Exception, or the NotAuthorizedException,
   * ResourceNotFoundException, BadXmlException, or MiscClientException thrown by the
   * WattDepotClient.
   */
  public DailyEnergy setAll(WattDepotClient client, String name, String day) 
      throws Exception {
    this.data = client.getLatestSensorData(name);
    this.data2 = client.getLatestSensorData(name);
    
    this.sourceName = name;
    this.dayString = day;
    setCalendar(day);
    setEnergy(client);
    return this;
  }
  
  /**
   * Verifies the arguments, executes the command, and prints the results to the screen.
   * 
   * @param args Space delimited string of arguments (i.e. "arg1 arg2 arg3").
   * @param client The WattDepot client that will be performing the queries.
   * @throws Exception If an exception was thrown by the command (i.e. bad arguments) or any of 
   * its function calls.
   */
  @SuppressWarnings("unused")
  @Override
  public void execute(String args, WattDepotClient client) throws Exception {
    String[] splitArgs = args.split("[ ]");
    try {
      String test1 = splitArgs[0];
      String test2 = splitArgs[1];
    }
    catch (Exception e) {
      this.testArg = false;
      throw incorrectArguments;
    }
    
    // Checks for exactly 2 arguments
    try {
      String tooMuch = splitArgs[2];
      if (splitArgs[2] != null) {
        this.testArg = false;
      }
    }
    catch (Exception e) {
      this.testArg = true;
    }
    if (!this.testArg) {
      throw incorrectArguments;
    }
    
    try {
      int year = Integer.parseInt(splitArgs[1].substring(0, 4));
      int month = Integer.parseInt(splitArgs[1].substring(5, 7));
      int day = Integer.parseInt(splitArgs[1].substring(8, 10));
    }
    catch (Exception e) {
      this.testArg = false;
      throw dateFormat;
    }

    // Test passes, execute this block.
    List<Source> sources = client.getSources();
    boolean match = false;
    // Checks if the 2nd argument matches a source name. Throw exception if no matches.
    for (Source source : sources) {
      if (splitArgs[0].equals(source.getName())) {
        match = true;
        testArg = true;
      }
    }
    if (!match) {
      this.testArg = false;
      throw new Exception("Error: Source \"" + splitArgs[0] + "\" does not exist.");
    }
    this.testArg = true;
    setAll(client, splitArgs[0], splitArgs[1]);
    System.out.println(this.toString());
  }
  
  /**
   * Constructs the DailyEnergy object.
   */
  public DailyEnergy() {
    // object is initialized by the setAll() Method.
  }
  
  /**
   * Sets the start and end times for each day.
   * @param dayParameter String format of date input
   * @throws Exception dateFormat
   */
  private void setCalendar(String dayParameter) throws Exception {
    boolean sameDay = false;
    int year;
    int month;
    int day;
    this.startTime = data.getTimestamp();
    this.endTime = data2.getTimestamp();
    
    // yyyy-mm-dd
    if (dayParameter.charAt(4) != '-' || dayParameter.charAt(7) != '-') {
      testArg = false;
      throw dateFormat;
    }
    year = Integer.parseInt(dayParameter.substring(0, 4));
    month = Integer.parseInt(dayParameter.substring(5, 7));
    day = Integer.parseInt(dayParameter.substring(8, 10));
    
    if (year == startTime.getYear() &&
        month == startTime.getMonth() && 
        day == startTime.getDay()) {
      sameDay = true;
    }
    
    startTime.setTime(0, 0, 0);
    startTime.setYear(year);
    startTime.setMonth(month);
    startTime.setDay(day);
    
    if (!sameDay) {
      endTime.setTime(23, 59, 59);
      endTime.setYear(year);
      endTime.setMonth(month);
      endTime.setDay(day);
    }
  }
  
  /**
   * sets the energy reading for the given day.
   * @param client wattdepot client
   * @throws Exception thrown exception
   */
  private void setEnergy(WattDepotClient client) throws Exception {
    DecimalFormat format = new DecimalFormat( "###0.00" );
    kilosUsed = client.getEnergyConsumed(sourceName, startTime, endTime, 15) / 1000;
    kilosUsed = new Double(format.format(kilosUsed)).doubleValue();
  }
  
  /**
   * returns the date string.
   * @return string value of date input.
   */
  public String getCalendar() {
    return this.dayString;
  }
  
  /**
   * Gets the start time.
   * @return start of day. 00:00:00
   */
  public XMLGregorianCalendar getStartTime () {
    return startTime;
  }
  
  /**
   * Gets the end time.
   * @return end of day. 00:00:00
   */
  public XMLGregorianCalendar getEndTime () {
    return endTime;
  }
  
  /**
   * returns the name of the source.
   * @return source name
   */
  public String getName() {
    return this.sourceName;
  }
  
  /**
   * returns the amount of energy used, in kilowatts.
   * @return kilowatts value
   */
  public double getKiloWattsUsed() {
    return this.kilosUsed;
  }
  
  /**
   * returns a nice string value.
   * @return String value of object.
   */
  @Override
  public String toString() {
    return this.sourceName + "'s energy consumption for " + dayString 
           + " was: " + kilosUsed + "kWh.";
  }
  
  /**
   * Tells JUnit if there was an error with arguments.
   * @return argument passed (true) or failed (false)
   */
  public boolean testArgs() {
    return testArg;
  }
  /**
   * Returns the string to be printed by the help command. Format:
   * "command-name [args1] [args2] .... \nDescription"
   * 
   * @return The string to be printed by the help command.
   */
  @Override
  public String getHelpString() {
    return "daily-energy [tower | lounge] [date]\n"
        + "Returns the energy in kWh used by the tower or lounge " 
        + "for the specified date (yyyy-mm-dd).";
  }
}
